//
//  HTTPRequestTool.m
//
//
//  Created by huangyibiao on 15/11/15.
//  Copyright © 2016年 GFENG. All rights reserved.
//

#import "HTTPRequestTool.h"
#import <CommonCrypto/CommonDigest.h>
#import <UIKit/UIKit.h>

@interface NSString (md5)

+ (NSString *)HTTPRequestTool_md5:(NSString *)string;

@end

@implementation NSString (md5)

+ (NSString *)HTTPRequestTool_md5:(NSString *)string {
    if (string == nil || [string length] == 0) {
        return nil;
    }

    unsigned char digest[CC_MD5_DIGEST_LENGTH], i;
    CC_MD5([string UTF8String], (int)[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding], digest);
    NSMutableString *ms = [NSMutableString string];

    for (i = 0; i < CC_MD5_DIGEST_LENGTH; i++) {
        [ms appendFormat:@"%02x", (int)(digest[i])];
    }

    return [ms copy];
}

@end

static NSString *sg_privateNetworkBaseUrl = nil;


#ifdef DEBUG
static BOOL sg_isEnableInterfaceDebug = YES;
#else
static BOOL sg_isEnableInterfaceDebug = NO;
#endif

static BOOL sg_shouldAutoEncode = NO;
static NSDictionary *sg_httpHeaders = nil;
static HTTPResponseType sg_responseType = kHTTPResponseTypeJSON;
static HTTPRequestType  sg_requestType  = kHTTPRequestTypeJSON;
static HTTPNetworkStatus sg_networkStatus = kHTTPNetworkStatusUnknown;
static NSMutableArray *sg_requestTasks;
static BOOL sg_cacheGet = YES;
static BOOL sg_cachePost = YES;
static BOOL sg_cachePut = NO;
static BOOL sg_cacheDelete = NO;
static BOOL sg_shouldCallbackOnCancelRequest = YES;
static NSTimeInterval sg_timeout = 60.0f;
static BOOL sg_shoulObtainLocalWhenUnconnected = NO;

@implementation HTTPRequestTool

+ (void)cacheGetRequest:(BOOL)isCacheGet shoulCachePost:(BOOL)shouldCachePost shoulCachePut:(BOOL)shoulCachePut shoulCacheDelete:(BOOL)shoulCacheDelete {
    sg_cacheGet = isCacheGet;
    sg_cachePost = shouldCachePost;
    sg_cachePut = shoulCachePut;
    sg_cacheDelete = shoulCacheDelete;
}

+ (void)updateBaseUrl:(NSString *)baseUrl {
    sg_privateNetworkBaseUrl = baseUrl;
}

+ (NSString *)baseUrl {
    return sg_privateNetworkBaseUrl;
}


+ (void)setTimeout:(NSTimeInterval)timeout {
    sg_timeout = timeout;
}

+ (void)obtainDataFromLocalWhenNetworkUnconnected:(BOOL)shouldObtain {
    sg_shoulObtainLocalWhenUnconnected = shouldObtain;
}

+ (void)enableInterfaceDebug:(BOOL)isDebug {
    sg_isEnableInterfaceDebug = isDebug;
}

+ (BOOL)isDebug {
    return sg_isEnableInterfaceDebug;
}

static inline NSString *cachePath() {
    return [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"Documents/%@",@"HTTPRequestToolCaches"]];
}

+ (void)clearCaches {
    NSString *directoryPath = cachePath();

    if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
        NSError *error = nil;
        [[NSFileManager defaultManager] removeItemAtPath:directoryPath error:&error];

        if (error) {
            NSLog(@"HTTPRequestTool clear caches error: %@", error);
        } else {
            NSLog(@"HTTPRequestTool clear caches ok");
        }
    }
}

+ (unsigned long long)totalCacheSize {
    NSString *directoryPath = cachePath();
    BOOL isDir = NO;
    unsigned long long total = 0;

    if ([[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:&isDir]) {
        if (isDir) {
            NSError *error = nil;
            NSArray *array = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:&error];

            if (error == nil) {
                for (NSString *subpath in array) {
                    NSString *path = [directoryPath stringByAppendingPathComponent:subpath];
                    NSDictionary *dict = [[NSFileManager defaultManager] attributesOfItemAtPath:path
                                                                                          error:&error];
                    if (!error) {
                        total += [dict[NSFileSize] unsignedIntegerValue];
                    }
                }
            }
        }
    }

    return total;
}

+ (NSMutableArray *)allTasks {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (sg_requestTasks == nil) {
            sg_requestTasks = [[NSMutableArray alloc] init];
        }
    });

    return sg_requestTasks;
}

+ (void)cancelAllRequest {
    @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(HTTPURLSessionTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task isKindOfClass:[HTTPURLSessionTask class]]) {
                [task cancel];
            }
        }];

        [[self allTasks] removeAllObjects];
    };
}

+ (void)cancelRequestWithURL:(NSString *)url {
    if (url == nil) {
        return;
    }

    @synchronized(self) {
        [[self allTasks] enumerateObjectsUsingBlock:^(HTTPURLSessionTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([task isKindOfClass:[HTTPURLSessionTask class]]
                    && [task.currentRequest.URL.absoluteString hasSuffix:url]) {
                [task cancel];
                [[self allTasks] removeObject:task];
                return;
            }
        }];
    };
}

+ (void)configRequestType:(HTTPRequestType)requestType
             responseType:(HTTPResponseType)responseType
      shouldAutoEncodeUrl:(BOOL)shouldAutoEncode
  callbackOnCancelRequest:(BOOL)shouldCallbackOnCancelRequest {
    sg_requestType = requestType;
    sg_responseType = responseType;
    sg_shouldAutoEncode = shouldAutoEncode;
    sg_shouldCallbackOnCancelRequest = shouldCallbackOnCancelRequest;
}

+ (BOOL)shouldEncode {
    return sg_shouldAutoEncode;
}

+ (void)configCommonHttpHeaders:(NSDictionary *)httpHeaders {
    sg_httpHeaders = httpHeaders;
}

+ (HTTPURLSessionTask *)getWithUrl:(NSString *)url
                      refreshCache:(BOOL)refreshCache
                           success:(HTTPResponseSuccess)success
                              fail:(HTTPResponseFail)fail {
    return [self getWithUrl:url
               refreshCache:refreshCache
                     params:nil
                    success:success
                       fail:fail];
}

+ (HTTPURLSessionTask *)getWithUrl:(NSString *)url
                      refreshCache:(BOOL)refreshCache
                            params:(NSDictionary *)params
                           success:(HTTPResponseSuccess)success
                              fail:(HTTPResponseFail)fail {
    return [self getWithUrl:url
               refreshCache:refreshCache
                     params:params
                   progress:nil
                    success:success
                       fail:fail];
}

+ (HTTPURLSessionTask *)getWithUrl:(NSString *)url
                      refreshCache:(BOOL)refreshCache
                            params:(NSDictionary *)params
                          progress:(HTTPGetProgress)progress
                           success:(HTTPResponseSuccess)success
                              fail:(HTTPResponseFail)fail {
    return [self _requestWithUrl:url
                    refreshCache:refreshCache
                     requestType:1
                       httpMedth:1
                          params:params
                        progress:progress
                         success:success
                            fail:fail];
}

+ (HTTPURLSessionTask *)postWithUrl:(NSString *)url
                       refreshCache:(BOOL)refreshCache
                             params:(NSDictionary *)params
                            success:(HTTPResponseSuccess)success
                               fail:(HTTPResponseFail)fail {
    return [self postWithUrl:url
                refreshCache:refreshCache
                 requestType:1
                      params:params
                    progress:nil
                     success:success
                        fail:fail];
}
+ (HTTPURLSessionTask *)postWithUrl:(NSString *)url
                       refreshCache:(BOOL)refreshCache
                        requestType:(HTTPRequestType)requestType
                             params:(NSDictionary *)params
                            success:(HTTPResponseSuccess)success
                               fail:(HTTPResponseFail)fail {
    return [self postWithUrl:url
                refreshCache:refreshCache
                 requestType:requestType
                      params:params
                    progress:nil
                     success:success
                        fail:fail];
}

+ (HTTPURLSessionTask *)postWithUrl:(NSString *)url
                       refreshCache:(BOOL)refreshCache
                        requestType:(HTTPRequestType)requestType
                             params:(NSDictionary *)params
                           progress:(HTTPPostProgress)progress
                            success:(HTTPResponseSuccess)success
                               fail:(HTTPResponseFail)fail {
    return [self _requestWithUrl:url
                    refreshCache:refreshCache
                     requestType:requestType
                       httpMedth:2
                          params:params
                        progress:progress
                         success:success
                            fail:fail];
}

+ (HTTPURLSessionTask *)putWithUrl:(NSString *)url
                    refreshCache:(BOOL)refreshCache
                          params:(NSDictionary *)params
                         success:(HTTPResponseSuccess)success
                              fail:(HTTPResponseFail)fail{
    return [self _requestWithUrl:url
                    refreshCache:refreshCache
                     requestType:sg_requestType
                       httpMedth:3
                          params:params
                        progress:nil
                         success:success
                            fail:fail];
}
+ (HTTPURLSessionTask *)putWithUrl:(NSString *)url
                      refreshCache:(BOOL)refreshCache
                       requestType:(HTTPRequestType)requestType
                            params:(NSDictionary *)params
                           success:(HTTPResponseSuccess)success
                              fail:(HTTPResponseFail)fail {
    return [self _requestWithUrl:url
                    refreshCache:refreshCache
                     requestType:requestType
                       httpMedth:3
                          params:params
                        progress:nil
                         success:success
                            fail:fail];
}

+ (HTTPURLSessionTask *)deleteWithUrl:(NSString *)url
                       refreshCache:(BOOL)refreshCache
                             params:(NSDictionary *)params
                            success:(HTTPResponseSuccess)success
                                 fail:(HTTPResponseFail)fail{
    return [self _requestWithUrl:url
                    refreshCache:refreshCache
                     requestType:sg_requestType
                       httpMedth:4
                          params:params
                        progress:nil
                         success:success
                            fail:fail];
}
+ (HTTPURLSessionTask *)deleteWithUrl:(NSString *)url
                         refreshCache:(BOOL)refreshCache
                          requestType:(HTTPRequestType)requestType
                               params:(NSDictionary *)params
                              success:(HTTPResponseSuccess)success
                                 fail:(HTTPResponseFail)fail {
    return [self _requestWithUrl:url
                    refreshCache:refreshCache
                     requestType:requestType
                       httpMedth:4
                          params:params
                        progress:nil
                         success:success
                            fail:fail];
}


+ (HTTPURLSessionTask *)_requestWithUrl:(NSString *)url
                           refreshCache:(BOOL)refreshCache
                            requestType:(HTTPRequestType)requestType
                              httpMedth:(NSUInteger)httpMethod
                                 params:(NSDictionary *)params
                               progress:(HTTPDownloadProgress)progress
                                success:(HTTPResponseSuccess)success
                                   fail:(HTTPResponseFail)fail {
    AFHTTPSessionManager *manager = [self manager];
    if (requestType == kHTTPRequestTypePlainText) {
        manager.requestSerializer = [AFHTTPRequestSerializer serializer];
    }
    NSString *absolute = [self absoluteUrlWithPath:url];
    if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    } else {
        NSURL *absouluteURL = [NSURL URLWithString:absolute];
        if (absouluteURL == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
    if ([self shouldEncode]) {
        url = [self encodeUrl:url];
    }
    if (refreshCache) {// 获取缓存
        id response = [HTTPRequestTool cahceResponseWithURL:absolute parameters:params];
        if (response) {
            if (success) {
                [self successResponse:response callback:success];
                if ([self isDebug]) {
                    [self logWithSuccessResponse:response url:absolute params:params];
                }
            }
        }
    }
    HTTPURLSessionTask *session = nil;

    if (httpMethod == 1) {
        params = [self addToken:params url:absolute];
        session = [manager GET:absolute parameters:params headers:NULL progress:^(NSProgress * _Nonnull downloadProgress) {
            if (progress) {
                progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
            }
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self successResponse:responseObject callback:success];
            if (refreshCache) {
                [self cacheResponseObject:responseObject request:absolute parameters:params];
            }
            [[self allTasks] removeObject:task];
            if ([self isDebug]) {
                [self logWithSuccessResponse:responseObject
                                         url:absolute
                                      params:params];
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [[self allTasks] removeObject:task];
            [self handleCallbackWithError:error fail:fail url:url paramsStr:params];

            if ([self isDebug]) {
                [self logWithFailError:error url:absolute params:params];
            }
        }];
    }
    else if (httpMethod == 2) {
//        absolute = [NSString stringWithFormat:@"%@?sign=%@",absolute,[self URLEncodedString:[self addToken:params url:absolute][@"sign"]]];
        session = [manager POST:absolute parameters:params headers:NULL progress:^(NSProgress * _Nonnull downloadProgress) {
            if (progress) {
                progress(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
            }
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self successResponse:responseObject callback:success];
            if (refreshCache) {
                [self cacheResponseObject:responseObject request:absolute  parameters:params];
            }
            [[self allTasks] removeObject:task];
            if ([self isDebug]) {
                [self logWithSuccessResponse:responseObject url:absolute params:params];
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [[self allTasks] removeObject:task];
            [self handleCallbackWithError:error fail:fail url:url paramsStr:params];
            if ([self isDebug]) {
                [self logWithFailError:error url:absolute params:params];
            }
        }];
    }
    else if (httpMethod == 3) {
        session = [manager PUT:absolute parameters:params headers:NULL success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self successResponse:responseObject callback:success];
            if (sg_cachePost) {
                [self cacheResponseObject:responseObject request:absolute  parameters:params];
            }
            [[self allTasks] removeObject:task];
            if ([self isDebug]) {
                [self logWithSuccessResponse:responseObject
                                         url:absolute
                                      params:params];
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [[self allTasks] removeObject:task];
            [self handleCallbackWithError:error fail:fail url:url paramsStr:params];
            if ([self isDebug]) {
                [self logWithFailError:error url:absolute params:params];
            }
        }];
    }
    else if (httpMethod == 4) {
        session = [manager DELETE:absolute parameters:params headers:NULL success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            [self successResponse:responseObject callback:success];
            if (sg_cachePost) {
                [self cacheResponseObject:responseObject request:absolute  parameters:params];
            }
            [[self allTasks] removeObject:task];
            if ([self isDebug]) {
                [self logWithSuccessResponse:responseObject url:absolute params:params];
            }
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            [[self allTasks] removeObject:task];
            [self handleCallbackWithError:error fail:fail url:url paramsStr:params];
            if ([self isDebug]) {
                [self logWithFailError:error url:absolute params:params];
            }
        }];
    }
    if (session) {
        [[self allTasks] addObject:session];
    }
    return session;
}

+ (HTTPURLSessionTask *)uploadFileWithUrl:(NSString *)url
                            uploadingFile:(NSString *)uploadingFile
                                 progress:(HTTPUploadProgress)progress
                                  success:(HTTPResponseSuccess)success
                                     fail:(HTTPResponseFail)fail {
    if ([NSURL URLWithString:uploadingFile] == nil) {
        HTTPAppLog(@"uploadingFile无效，无法生成URL。请检查待上传文件是否存在");
        return nil;
    }

    NSURL *uploadURL = nil;
    if ([self baseUrl] == nil) {
        uploadURL = [NSURL URLWithString:url];
    } else {
        uploadURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]];
    }

    if (uploadURL == nil) {
        HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文或特殊字符，请尝试Encode URL");
        return nil;
    }

    AFHTTPSessionManager *manager = [self manager];
    NSURLRequest *request = [NSURLRequest requestWithURL:uploadURL];
    HTTPURLSessionTask *session = nil;

    [manager uploadTaskWithRequest:request fromFile:[NSURL URLWithString:uploadingFile] progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
    } completionHandler:^(NSURLResponse * _Nonnull response, id  _Nullable responseObject, NSError * _Nullable error) {
        [[self allTasks] removeObject:session];

        [self successResponse:responseObject callback:success];

        if (error) {
            [self handleCallbackWithError:error fail:fail url:url paramsStr:nil];

            if ([self isDebug]) {
                [self logWithFailError:error url:response.URL.absoluteString params:nil];
            }
        } else {
            if ([self isDebug]) {
                [self logWithSuccessResponse:responseObject
                                         url:response.URL.absoluteString
                                      params:nil];
            }
        }
    }];

    if (session) {
        [[self allTasks] addObject:session];
    }

    return session;
}

+ (HTTPURLSessionTask *)uploadWithImage:(UIImage *)image
                                    url:(NSString *)url
                               filename:(NSString *)filename
                                   name:(NSString *)name
                               mimeType:(NSString *)mimeType
                             parameters:(NSDictionary *)parameters
                               progress:(HTTPUploadProgress)progress
                                success:(HTTPResponseSuccess)success
                                   fail:(HTTPResponseFail)fail {
    if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    } else {
        if ([NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:parameters];

    dic[@"deviceType"] = @"ios";

    parameters = dic;

    if ([self shouldEncode]) {
        url = [self encodeUrl:url];
    }

    NSString *absolute = [self absoluteUrlWithPath:url];

//    absolute = [NSString stringWithFormat:@"%@?sign=%@",absolute,[self URLEncodedString:[self addToken:parameters url:absolute][@"sign"]]];

    AFHTTPSessionManager *manager = [self manager];
    HTTPURLSessionTask *session = [manager POST:absolute parameters:parameters headers:NULL constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        if (image != nil){
            NSData *imageData = UIImageJPEGRepresentation(image, 1);

            NSString *imageFileName = filename;
            if (filename == nil || ![filename isKindOfClass:[NSString class]] || filename.length == 0) {
                NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
                formatter.dateFormat = @"yyyyMMddHHmmss";
                NSString *str = [formatter stringFromDate:[NSDate date]];
                imageFileName = [NSString stringWithFormat:@"%@.jpg", str];
            }
            // 上传图片，以文件流的格式
            [formData appendPartWithFileData:imageData name:name fileName:imageFileName mimeType:mimeType];
        }
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [[self allTasks] removeObject:task];
        [self successResponse:responseObject callback:success];

        if ([self isDebug]) {
            [self logWithSuccessResponse:responseObject
                                     url:absolute
                                  params:parameters];
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [[self allTasks] removeObject:task];

        [self handleCallbackWithError:error fail:fail url:url paramsStr:parameters];

        if ([self isDebug]) {
            [self logWithFailError:error url:absolute params:nil];
        }
    }];

    [session resume];
    if (session) {
        [[self allTasks] addObject:session];
    }

    return session;
}
+ (void)uploadWithImageArr:(NSArray *)imageArr
                       url:(NSString *)url
                       num:(int)num
                parameters:(NSDictionary *)parameters
                  progress:(HTTPUploadProgress)progress
                   success:(HTTPResponseSuccess)success
                      fail:(HTTPResponseFail)fail{
    NSDictionary *iamgeDic = imageArr[num];
    [self uploadWithImage:iamgeDic[@"image"] url:url parameters:parameters progress:progress success:^(id response) {
        if (imageArr.count == num + 1) {
            if (success) {
                success(response);
            }
        }
        else{
            [self uploadWithImageArr:imageArr
                                 url:url
                                 num:(num+1)
                          parameters:parameters
                            progress:progress
                             success:success
                                fail:fail];
        }
    } fail:^(NSError *error) {
        if (imageArr.count == num + 1) {
            if (success) {
                success(@"失败了");
            }
        }
        else{
            [self uploadWithImageArr:imageArr
                                 url:url
                                 num:(num+1)
                          parameters:parameters
                            progress:progress
                             success:success
                                fail:fail];
        }
    }];
}
+ (HTTPURLSessionTask *)uploadWithImage:(UIImage *)image
                                    url:(NSString *)url
                             parameters:(NSDictionary *)parameters
                               progress:(HTTPUploadProgress)progress
                                success:(HTTPResponseSuccess)success
                                   fail:(HTTPResponseFail)fail {
    if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
    else {
        if ([NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
    if ([self shouldEncode]) {
        url = [self encodeUrl:url];
    }
    NSString *absolute = [self absoluteUrlWithPath:url];
    AFHTTPSessionManager *manager = [self manager];
//    absolute = [NSString stringWithFormat:@"%@?sign=%@",absolute,[self URLEncodedString:[self addToken:parameters url:absolute][@"sign"]]];
    HTTPURLSessionTask *session = [manager POST:absolute parameters:parameters headers:NULL constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
        NSData *imageData = UIImageJPEGRepresentation(image, 1);
        HTTPAppLog(@"图片大小：%.2f MB",imageData.length /1024.f/1024.f);
        [formData appendPartWithFileData:imageData name:@"file" fileName:@"jpg" mimeType:[self typeForImageData:imageData type:YES]];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [[self allTasks] removeObject:task];
        [self successResponse:responseObject callback:success];
        if ([self isDebug]) {
            [self logWithSuccessResponse:responseObject
                                     url:absolute
                                  params:parameters];
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [[self allTasks] removeObject:task];
        [self handleCallbackWithError:error fail:fail url:url paramsStr:parameters];
        if ([self isDebug]) {
            [self logWithFailError:error url:absolute params:nil];
        }
    }];
    [session resume];
    if (session) {
        [[self allTasks] addObject:session];
    }
    return session;
}
+ (HTTPURLSessionTask *)uploadWithVideo:(NSData *)video
                                    url:(NSString *)url
                             parameters:(NSDictionary *)parameters
                               progress:(HTTPUploadProgress)progress
                                success:(HTTPResponseSuccess)success
                                   fail:(HTTPResponseFail)fail {
    if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
    else {
        if ([NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
    if ([self shouldEncode]) {
        url = [self encodeUrl:url];
    }
    NSString *absolute = [self absoluteUrlWithPath:url];
    AFHTTPSessionManager *manager = [self manager];
    HTTPURLSessionTask *session = [manager POST:absolute parameters:parameters headers:NULL constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData) {
//        NSData *videoData = video;
//        [formData appendPartWithFileData:[NSData new] name:@"importFile" fileName:@"sadfsa" mimeType:@"mp4"];
    } progress:^(NSProgress * _Nonnull uploadProgress) {
        if (progress) {
            progress(uploadProgress.completedUnitCount, uploadProgress.totalUnitCount);
        }
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        [[self allTasks] removeObject:task];
        [self successResponse:responseObject callback:success];
        if ([self isDebug]) {
            [self logWithSuccessResponse:responseObject
                                     url:absolute
                                  params:parameters];
        }
    } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
        [[self allTasks] removeObject:task];
        [self handleCallbackWithError:error fail:fail url:url paramsStr:parameters];
        if ([self isDebug]) {
            [self logWithFailError:error url:absolute params:nil];
        }
    }];
    [session resume];
    if (session) {
        [[self allTasks] addObject:session];
    }
    return session;
}

/**
 * 判断图片数据类型
 * @param data 二进制数据
 * @param type 格式或者类型
 * @return 类型
 */
+ (NSString *)typeForImageData:(NSData *)data type:(BOOL)type {
    uint8_t c;
    [data getBytes:&c length:1];
    switch (c) {
        case 0xFF:
            return type?@"image/jpeg":@"jpg";
        case 0x89:
            return type?@"image/png":@"png";
        case 0x47:
            return type?@"image/gif":@"gif";
        case 0x49:
        case 0x4D:
            return type?@"image/tiff":@"tiff";
    }
    return nil;
}


+ (HTTPURLSessionTask *)downloadWithUrl:(NSString *)url
                               progress:(HTTPDownloadProgress)progressBlock
                                success:(HTTPResponseSuccess)success
                                failure:(HTTPResponseFail)failure {
    if ([self baseUrl] == nil) {
        if ([NSURL URLWithString:url] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    } else {
        if ([NSURL URLWithString:[NSString stringWithFormat:@"%@%@", [self baseUrl], url]] == nil) {
            HTTPAppLog(@"URLString无效，无法生成URL。可能是URL中有中文，请尝试Encode URL");
            return nil;
        }
    }
//    if (!saveToPath){
//        NSString *tmpPaht = NSTemporaryDirectory();
//        [downloadURL URLByAppendingPathComponent:response.suggestedFilename];
//        saveToPath = tmpPaht;
//    }
    NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
    AFHTTPSessionManager *manager = [self manager];
    HTTPURLSessionTask *session = nil;
    session = [manager downloadTaskWithRequest:downloadRequest progress:^(NSProgress * _Nonnull downloadProgress) {
        if (progressBlock) {
            progressBlock(downloadProgress.completedUnitCount, downloadProgress.totalUnitCount);
        }
    } destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
        NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"tmp/"]];
        NSURL *downloadURL = [NSURL fileURLWithPath:path];
        NSURL *url = [downloadURL URLByAppendingPathComponent:response.suggestedFilename];
        return url;
    } completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
        [[self allTasks] removeObject:session];
        if (error == nil) {
            if (success) {
                success(filePath.absoluteString);
            }
            if ([self isDebug]) {
                HTTPAppLog(@"下载成功 url %@", [self absoluteUrlWithPath:url]);
            }
        } else {
            [self handleCallbackWithError:error fail:failure url:url  paramsStr:nil];
            if ([self isDebug]) {
                HTTPAppLog(@"下载失败 url %@, 理由 : %@", [self absoluteUrlWithPath:url], [error description]);
            }
        }
    }];
    [session resume];
    if (session) {
        [[self allTasks] addObject:session];
    }
    return session;
}

#pragma mark - Private
+ (AFHTTPSessionManager *)manager {
    AFHTTPSessionManager *manager = nil;;
    if ([self baseUrl] != nil) {
        manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:[self baseUrl]]];
    } else {
        manager = [AFHTTPSessionManager manager];
    }
    //添加https证书
//    [manager setSecurityPolicy:[self customSecurityPolicy]];
    switch (sg_requestType) {
        case kHTTPRequestTypeJSON: {
            manager.requestSerializer = [AFJSONRequestSerializer serializer];
            break;
        }
        case kHTTPRequestTypePlainText: {
            manager.requestSerializer = [AFHTTPRequestSerializer serializer];
            break;
        }
        default: {
            break;
        }
    }
    switch (sg_responseType) {
        case kHTTPResponseTypeJSON: {
            manager.responseSerializer = [AFJSONResponseSerializer serializer];
            break;
        }
        case kHTTPResponseTypeXML: {
            manager.responseSerializer = [AFXMLParserResponseSerializer serializer];
            break;
        }
        case kHTTPResponseTypeData: {
            manager.responseSerializer = [AFHTTPResponseSerializer serializer];
            break;
        }
        default: {
            break;
        }
    }
    manager.requestSerializer.stringEncoding = NSUTF8StringEncoding;
    for (NSString *key in sg_httpHeaders.allKeys) {
        if (sg_httpHeaders[key] != nil) {
            [manager.requestSerializer setValue:sg_httpHeaders[key] forHTTPHeaderField:key];
        }
    }
    //添加请求头信息
    [manager.requestSerializer setValue:[UserModel_WL token] forHTTPHeaderField:@"token"];

    manager.responseSerializer.acceptableContentTypes = [NSSet setWithArray:@[@"application/json", @"text/html", @"text/json", @"text/plain", @"text/javascript", @"text/xml", @"image/*"]];
    manager.requestSerializer.timeoutInterval = sg_timeout;
    // 设置允许同时最大并发数量，过大容易出问题
    manager.operationQueue.maxConcurrentOperationCount = 3;
    if (sg_shoulObtainLocalWhenUnconnected && (sg_cacheGet || sg_cachePost ) ) {
        [self detectNetwork:nil];
    }
    return manager;
}
#pragma mark -- https证书配置
+ (AFSecurityPolicy*)customSecurityPolicy {
    NSString *cerPath = [[NSBundle mainBundle] pathForResource:@"d" ofType:@"cer"];
    NSData *certData = [NSData dataWithContentsOfFile:cerPath];
    AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate];
    [securityPolicy setAllowInvalidCertificates:NO];
    NSSet *set = [NSSet setWithObjects:certData, nil];
    [securityPolicy setPinnedCertificates:set];
    return securityPolicy;
}

+ (void)detectNetwork:(void (^)(HTTPNetworkStatus bytesRead))networkStatusBlock{
    AFNetworkReachabilityManager *reachabilityManager = [AFNetworkReachabilityManager sharedManager];
    [reachabilityManager startMonitoring];
    [reachabilityManager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
        if (status == AFNetworkReachabilityStatusNotReachable){
            sg_networkStatus = kHTTPNetworkStatusNotReachable;
        }else if (status == AFNetworkReachabilityStatusUnknown){
            sg_networkStatus = kHTTPNetworkStatusUnknown;
        }else if (status == AFNetworkReachabilityStatusReachableViaWWAN){
            sg_networkStatus = kHTTPNetworkStatusReachableViaWWAN;
        }else if (status == AFNetworkReachabilityStatusReachableViaWiFi){
            sg_networkStatus = kHTTPNetworkStatusReachableViaWiFi;
        }
        if(networkStatusBlock){
            networkStatusBlock(sg_networkStatus);
        }
    }];
}

/**
 * 添加额外参数
 * @param params 参数
 * @param absolute 地址
 * @return 心参数
 */
+(NSDictionary *)addToken:(NSDictionary *)params url:(NSString *)absolute{
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:params];
    return dic;
}
+(NSString *)URLEncodedString:(NSString *)str {
    NSString *encodedString = (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (__bridge CFStringRef)str, NULL, (CFStringRef)@"!*'();:@&=+$,/?%#[]", kCFStringEncodingUTF8));
    return encodedString;
}
///冒泡排序
- (NSArray *)change:(NSMutableArray *)array{
    if (array.count > 1) {
        for (int  i =0; i<[array count]-1; i++) {
            for (int j = i+1; j<[array count]; j++) {
                if ([array[i] intValue]>[array[j] intValue]) {
                    //交换
                    [array exchangeObjectAtIndex:i withObjectAtIndex:j];
                }
            }
        }
    }
    NSArray * resultArray = [[NSArray alloc]initWithArray:array];
    return resultArray;
}
+ (void)logWithSuccessResponse:(id)response url:(NSString *)url params:(NSDictionary *)params {
    HTTPAppLog(@"请求地址：%@\n参数:%@\n参数json:%@\n结果:%@\n", [self generateGETAbsoluteURL:url params:params], params,[params yy_modelToJSONString], response);
}

+ (void)logWithFailError:(NSError *)error url:(NSString *)url params:(id)params {
    NSString *format = @"参数: ";
    if (params == nil || ![params isKindOfClass:[NSDictionary class]]) {
        format = @"";
        params = @"";
    }
    if ([error code] == NSURLErrorCancelled) {
        HTTPAppLog(@"请求失败地址: %@\n%@%@\n", url, format, params);
    } else {
        HTTPAppLog(@"请求失败地址: %@\n%@%@\n失败原因:%@\n", [self generateGETAbsoluteURL:url params:params], format, params, [error localizedDescription]);
    }
    
    
    if (error.userInfo){
        NSData *data = error.userInfo[@"com.alamofire.serialization.response.error.data"];
        if (data){
            NSString *result =[[ NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            HTTPAppLog(@"请求失败内容: %@", result);
        }
    }
}
// 仅对一级字典结构起作用
+ (NSString *)generateGETAbsoluteURL:(NSString *)url params:(id)params {
    if (params == nil || ![params isKindOfClass:[NSDictionary class]] || [params count] == 0) {
        return url;
    }
    NSString *queries = @"";
    for (NSString *key in params) {
        id value = [params objectForKey:key];
        if ([value isKindOfClass:[NSDictionary class]]) {
            continue;
        } else if ([value isKindOfClass:[NSArray class]]) {
            continue;
        } else if ([value isKindOfClass:[NSSet class]]) {
            continue;
        } else {
            queries = [NSString stringWithFormat:@"%@%@=%@&", (queries.length == 0 ? @"&" : queries), key, value];
        }
    }
    if (queries.length > 1) {
        queries = [queries substringToIndex:queries.length - 1];
    }
    if (([url hasPrefix:@"http://"] || [url hasPrefix:@"https://"]) && queries.length > 1) {
        if ([url rangeOfString:@"?"].location != NSNotFound
                || [url rangeOfString:@"#"].location != NSNotFound) {
            url = [NSString stringWithFormat:@"%@%@", url, queries];
        } else {
            queries = [queries substringFromIndex:1];
            url = [NSString stringWithFormat:@"%@?%@", url, queries];
        }
    }
    return url.length == 0 ? queries : url;
}

+ (NSString *)encodeUrl:(NSString *)url {
    return [self HTTP_URLEncode:url];
}

+ (id)tryToParseData:(id)responseData {
    if ([responseData isKindOfClass:[NSData class]]) {
        // 尝试解析成JSON
        if (responseData == nil) {
            return responseData;
        } else {
            NSError *error = nil;
            NSDictionary *response = [NSJSONSerialization JSONObjectWithData:responseData options:NSJSONReadingMutableContainers error:&error];
            if (error != nil) {
                return responseData;
            } else {
                return response;
            }
        }
    } else {
        return responseData;
    }
}

+ (void)successResponse:(id)responseData callback:(HTTPResponseSuccess)success {
    if (success) {
        id topic = [self tryToParseData:responseData];
        if ([[topic class]isSubclassOfClass:[NSDictionary class]]) {
            if ([topic objectForKey:@"code"]){
                NSInteger code = [[topic objectForKey:@"code"] integerValue];
                if (code == 201) {
                    [RW_UserModel removeModel];
                }
            }
            success(topic);
        } else if ([[topic class]isSubclassOfClass:[NSXMLParser class]]) {
            NSXMLParser *xml = topic;
            NSLog(@"%@",xml);
        } else{
            success(topic);
        }
    }
}

//+ (void)starButtonClicked:(id)sender{
//    //先将未到时间执行前的任务取消。
//    [[self class] cancelPreviousPerformRequestsWithTarget:self selector:@selector(todoSomething:) object:sender];
//    [self performSelector:@selector(todoSomething:) withObject:sender afterDelay:0.3f];
//}


+ (NSString *)HTTP_URLEncode:(NSString *)url {
    NSString *newString =
            CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
                    (__bridge CFStringRef)url,
                    NULL,
                    CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding)));
    if (newString) {
        return newString;
    }

    return url;
}

+ (id)cahceResponseWithURL:(NSString *)url parameters:params {
    id cacheData = nil;
    if (url) {
        // Try to get datas from disk
        NSString *directoryPath = cachePath();
        NSString *absoluteURL = [self generateGETAbsoluteURL:url params:params];
        NSString *key = [NSString HTTPRequestTool_md5:absoluteURL];
        NSString *path = [directoryPath stringByAppendingPathComponent:key];
        NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
        if (data) {
            cacheData = data;
            HTTPAppLog(@"读取缓存数据: %@\n", url);
        }
    }
    return cacheData;
}

+ (void)cacheResponseObject:(id)responseObject request:(NSString *)url parameters:params {
    if (url && responseObject && ![responseObject isKindOfClass:[NSNull class]]) {
        NSString *directoryPath = cachePath();
        NSError *error = nil;
        if (![[NSFileManager defaultManager] fileExistsAtPath:directoryPath isDirectory:nil]) {
            [[NSFileManager defaultManager] createDirectoryAtPath:directoryPath withIntermediateDirectories:YES attributes:nil error:&error];
            if (error) {
                HTTPAppLog(@"创建缓存目录错误: %@\n", error);
                return;
            }
        }

        NSString *absoluteURL = [self generateGETAbsoluteURL:url params:params];
        NSString *key = [NSString HTTPRequestTool_md5:absoluteURL];

        NSString *path = [directoryPath stringByAppendingPathComponent:key];
        NSDictionary *dict = (NSDictionary *)responseObject;
        NSData *data = nil;
        if ([dict isKindOfClass:[NSData class]]) {
            data = responseObject;
        } else {
            data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
        }
        if (data && error == nil) {
            BOOL isOk = [[NSFileManager defaultManager] createFileAtPath:path contents:data attributes:nil];
            if (isOk) {
                HTTPAppLog(@"请求网址: %@\n params:%@", url,params);
            } else {
                HTTPAppLog(@"请求失败网址: %@\n params:%@", url,params);
            }
        }
    }
}

+ (NSString *)absoluteUrlWithPath:(NSString *)path {
    if (path == nil || path.length == 0) {
        return @"";
    }
    if ([self baseUrl] == nil || [[self baseUrl] length] == 0) {
        return path;
    }
    NSString *absoluteUrl = path;
    if (![path hasPrefix:@"http://"] && ![path hasPrefix:@"https://"]) {
        if ([[self baseUrl] hasSuffix:@"/"]) {
            if ([path hasPrefix:@"/"]) {
                NSMutableString * mutablePath = [NSMutableString stringWithString:path];
                [mutablePath deleteCharactersInRange:NSMakeRange(0, 1)];
                absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], mutablePath];
            }else {
                absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], path];
            }
        }else {
            if ([path hasPrefix:@"/"]) {
                absoluteUrl = [NSString stringWithFormat:@"%@%@",[self baseUrl], path];
            }else {
                absoluteUrl = [NSString stringWithFormat:@"%@/%@",[self baseUrl], path];
            }
        }
    }

    return absoluteUrl;
}

+ (void)handleCallbackWithError:(NSError *)error fail:(HTTPResponseFail)fail url:(NSString *)url paramsStr:(NSDictionary *)paramsStr {
    if ([error code] == NSURLErrorCancelled) {
        if (sg_shouldCallbackOnCancelRequest) {
            if (fail) {
                fail(error);
            }
        }
    } else {
        if (fail) {
            fail(error);
        }
    }
}

+(id)readCachingUrl:(NSString *)url params:(NSDictionary *)param{
    id data = [self tryToParseData:[self cahceResponseWithURL:[self absoluteUrlWithPath:url] parameters:param]];
    NSLog(@"%@",data);
    return nil;
}
/**
 获取当前网络状态
 */
+ (HTTPNetworkStatus)getNetWorkState{
    return sg_networkStatus;
}

@end
